/*
 * MasterRoutine.cpp
 *
 *  Created on: 25/02/2014
 *      Author: root
 */

#include "MasterRoutine.h"
#include <iostream>
#include <list>

using namespace std;

extern int rank, size;
extern DppmSpec * dppm;


int MasterRoutine(){


	list<int*> subRanges;

	Tuple * bestSolution = new Tuple();

	int numAct = dppm->getNumActivities();
	int doneProcsCount = size - 1; //number of slaves
	int doneProcs[size - 1];
	int whoFindBestSol = 0;
	memset(doneProcs,0, sizeof(int) * (size-1) );
	int msg;
	int tag;
	int idleProc;
	int busierProc;
	int idleProcTag;
	int busierProcTag;
	int cand[Tuple::tuplesIntSize];
	int * range;
	int maxRange[2];

	//Incializa los parametros para calcular los indices de las tuplas
	int * indBases;
	int indLen;
	defineIndexesParams(dppm,indLen,indBases);

	//Definir subrangos
	int numIndexes = dppm->getActivityNumModes(0) * indBases[0];

	int sizeSubRanges = (size-1);// * QUOTA;

	int div = numIndexes / sizeSubRanges;
	int mod = numIndexes % sizeSubRanges;

	for(int i = 1; i <= sizeSubRanges; i++){

		range = new int[2];
		range[0] = (i - 1) < mod ? ((div + 1) * (i - 1) ) : ((div + 1) * mod   +  div * ((i - 1) - mod));
		range[1] = i < mod       ? ((div + 1) * i) - 1    : ((div + 1) * mod   +  div * (i - mod)) - 1;
		subRanges.push_back(range);

	}

	MPI_Status status;

	while (doneProcsCount) {

		MPI_Recv(&msg, 1, MPI_INT, MPI_ANY_SOURCE, MPI_ANY_TAG, MPI_COMM_WORLD, &status);

		switch (status.MPI_TAG) {

		case BEST_SOLUTION_UPDATE:

			debugPrinter(0, rank, "MasterRoutine.cpp", 72, "BEST_SOLUTION_UPDATE");
			MPI_Recv(cand, Tuple::tuplesIntSize, MPI_INT, status.MPI_SOURCE,status.MPI_TAG, MPI_COMM_WORLD, &status);

			if (evalSolution(cand, bestSolution)) {
				whoFindBestSol = status.MPI_SOURCE;
				debugPrinter(0, rank, "MasterRoutine.cpp", 77, "BEST_SOLUTION_UPDATE",
								"find Slave",whoFindBestSol,"cost",bestSolution->cost());
				for (int i = 1; i < size; i++) {
					if( (!doneProcs[i - 1] ) && (i != status.MPI_SOURCE)){
						MPI_Send(&msg, 1, MPI_INT, i, BEST_SOLUTION_UPDATE, MPI_COMM_WORLD);
						MPI_Send(cand, Tuple::tuplesIntSize, MPI_INT, i, BEST_SOLUTION_UPDATE, MPI_COMM_WORLD);
					}
				}

			}
			break;

		case PROCESS_DONE:

			msg = subRanges.empty() ? FREE_TO_GO : NEW_RANGE;
			MPI_Send(&msg, 1, MPI_INT, status.MPI_SOURCE, PROCESS_DONE, MPI_COMM_WORLD);

			if(msg == NEW_RANGE){

				range = subRanges.front();
				subRanges.pop_front();
				MPI_Send(range, 2, MPI_INT, status.MPI_SOURCE, PROCESS_DONE, MPI_COMM_WORLD);
				debugPrinter(0, rank, "MasterRoutine.cpp", 97, "NEW_RANGE","slave rank", status.MPI_SOURCE , "range[0]",range[0],"range[1]",range[1],"subRanges size",subRanges.size());
				delete[] range;

			}else{

				doneProcsCount--;
				doneProcs[status.MPI_SOURCE - 1] = 1;
				debugPrinter(0, rank, "MasterRoutine.cpp", 105, "FREE_TO_GO","slave rank",rank);
			}
			break;
		}

	}

	debugPrinter(0, rank, "main", 176, "La mejor solución: ","Slave", whoFindBestSol , "Costo", bestSolution->cost(),"Tiempo",bestSolution->partialTimes(numAct-1));
	printf("\n\nLa mejor solución es: \n");
	bestSolution->print();

	delete bestSolution;
	delete [] indBases;

	return 0;

}

